﻿using System;
using System.Text;
using SCG = System.Collections.Generic;

using Nemerle.Assertions;
using Nemerle.Utility;

namespace Nemerle.OpenCL {

    public sealed class ProgramBuildOptions {

        public this(device : Device) {
            this.devices.Add(device);
        }

        public this(devices : SCG.IEnumerable[Device]) {
            this.devices.AddRange(devices);
        }

        [Accessor] devices : SCG.List[Device] = SCG.List();

        /* Preprocessor */
        [Accessor] defines : SCG.Dictionary[string, string] = SCG.Dictionary();
        [Accessor] includes : SCG.List[string] = SCG.List();

        /* Math */
        [Accessor(flags = WantSetter)] mutable single_precision_constant : bool;
        [Accessor(flags = WantSetter)] mutable denorms_are_zero : bool;

        /* Optimizations */
        [Accessor(flags = WantSetter)] mutable disable_optimization : bool;
        [Accessor(flags = WantSetter)] mutable strict_aliasing : bool;
        [Accessor(flags = WantSetter)] mutable enable_MAD : bool;
        [Accessor(flags = WantSetter)] mutable no_signed_zeros : bool;
        [Accessor(flags = WantSetter)] mutable unsafe_math_optimizations : bool;
        [Accessor(flags = WantSetter)] mutable finite_math_only : bool;
        [Accessor(flags = WantSetter)] mutable fast_relaxed_math : bool;

        /* Warnings */
        [Accessor(flags = WantSetter)] mutable suppress_warnings : bool;
        [Accessor(flags = WantSetter)] mutable warnings_as_errors : bool;

        public GetCompilerOptions() : string {
            def sb = StringBuilder();

            /* Preprocessor */
            foreach(pair in defines) {
                if(string.IsNullOrEmpty(pair.Value))
                    _ = sb.Append(" -D ").Append(pair.Key);
                else
                    _ = sb.Append(" -D \"").Append(pair.Key).Append("=").Append(pair.Value).Append("\"");
            }
            foreach(include in includes) {
                _ = sb.Append(" -I ").Append("\"").Append(include).Append("\"");
            }

            /* Math */
            when(single_precision_constant)
                _ = sb.Append(" -cl-single-precision-constant");
            when(denorms_are_zero)
                _ = sb.Append(" -cl-denorms-are-zero");

            /* Optimizations */
            when(disable_optimization)
                _ = sb.Append(" -cl-opt-disable");
            when(strict_aliasing)
                _ = sb.Append(" -cl-strict-aliasing");
            when(enable_MAD)
                _ = sb.Append(" -cl-mad-enable");
            when(no_signed_zeros)
                _ = sb.Append(" -cl-no-signed-zeros");
            when(unsafe_math_optimizations)
                _ = sb.Append(" -cl-unsafe-math-optimizations");
            when(finite_math_only)
                _ = sb.Append(" -cl-finite-math-only");
            when(fast_relaxed_math)
                _ = sb.Append(" -cl-fast-relaxed-math");

            /* Warnings */
            when(suppress_warnings)
                _ = sb.Append(" -w");
            when(warnings_as_errors)
                _ = sb.Append(" -Werror");

            sb.ToString();
        }

        public override ToString() : string {
            GetCompilerOptions()
        }

    }

}